package org.hackystat.devcathlon.engine.user;

import java.util.List;

import org.hackystat.devcathlon.engine.db.hibernate.HibernateUtil;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 * A thread-safe singleton class that manages access to the Teams in this system. 
 * @author Philip Johnson
 */
public class UserManager {
  /** The singleton instance. */
  private static UserManager theInstance = new UserManager();
  
  /** The private constructor. */
  private UserManager() {
    // does nothing at this point; will initialize from database later.
  }

  /**
   * Returns the singleton instance of the UserManager.
   * @return The UserManager.
   */
  public static UserManager getInstance() {
    return UserManager.theInstance;
  }
  
  /**
   * Adds a new user given the user instance.
   * 
   * @param user The user instance.
   * @return The user.
   */
  public synchronized User addUser(User user) {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      session.saveOrUpdate(user);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return user;
  }

  /**
   * Adds a new user to the system. 
   * @param firstName The first name of the user. 
   * @param lastName The last name of the user. 
   * @param email The user's email (and Hackystat account).
   * @param password The Hackystat password. 
   * @return The new User instance, if successful. 
   */
  public synchronized User addUser(String firstName, String lastName, String email, String password)
  {
    // Probably should check to see that the user is registered with Hackystat?
    User user = getUser(email);
    if (null != user) {
      return user;
    }
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      user = new User(firstName, lastName, email, password);
      user.setUsername(email);
      session.saveOrUpdate(user);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return user;
  }
  
  /**
   * Returns the User instance associated with the email, or null if not found. 
   * @param email The email of the User of interest. 
   * @return The User instance, or null if not found. 
   */
  public synchronized User getUser(String email) {
    User user = null;
    String hqlSelect = "from User u where u.email = :email";
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      Query query = session.createQuery(hqlSelect).setString("email", email);
      user = (User) query.uniqueResult();
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return user;
  }
  
  /**
   * Updates a specified user.
   * 
   * @param user The user.
   * @return The updated user.
   */
  public synchronized User updateUser(User user) {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      session.update(user);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return user;
  }
  
  /**
   * Removes the specified user from the map of users. 
   * Does nothing if this user is not currently on the map.
   * @param email The email of the user to remove. 
   */
  public synchronized void deleteUser (String email) {
    User user = getUser(email);
    if (null == user) {
      return;
    }
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      session.delete(user);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
  }
  
  /**
   * Gets a list of all Users in the system.
   * 
   * @return The list of Users.
   */
  public synchronized List<?> getUsers() {
    List<?> list = null;
    String hqlSelect = "from User";
    
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      Query query = session.createQuery(hqlSelect);
      list = query.list();
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return list;
  }
}
